#include "csapp.h"

typedef struct            
{
    int maxfd;            
    fd_set read_set;      
    fd_set ready_set;    
    int nready;          
    int maxi;            
    int clientfd[FD_SETSIZE];            
    rio_t clientrio[FD_SETSIZE];        
}pool;

int byte_cnt = 0;  

void init_pool(int listenfd, pool *p);
void add_client(int connfd, pool *p);
void check_clients(pool *p);

int main(int argc, char **argv)
{
    int listenfd, connfd, port, clen;
    struct sockaddr_in cliaddr;
    struct sockaddr_in seraddr;
    struct hostent *hp;
    char *haddrp;
    pid_t pid;
    static  pool pool;

   //参数的判断与处理
    if(argc != 2)
    {
        fprintf(stderr, "usage: %s \n", argv[0]);
        exit(0);
    }

    port = atoi(argv[1]);
 
   //套接字的初始化，创建
    listenfd = Socket(AF_INET, SOCK_STREAM, 0);
    bzero(&seraddr, sizeof(seraddr));
    seraddr.sin_family = AF_INET;
    seraddr.sin_port = htons(port);
    seraddr.sin_addr.s_addr = htonl(INADDR_ANY);

   //套接字的绑定
    Bind(listenfd, (SA*)&seraddr, sizeof(seraddr));

    Listen(listenfd, LISTENQ);
     init_pool(listenfd, &pool);                                     //初始化POOL池结构，为接下来的操作做准备

    while(1)
    {
       
        pool.ready_set = pool.read_set;
        pool.nready = Select(pool.maxfd+1, &pool.ready_set, NULL, NULL, NULL);    //select操作

       
        if(FD_ISSET(listenfd, &pool.ready_set))
        {
            clen = sizeof(cliaddr);
            connfd = Accept(listenfd, (SA*)&cliaddr, &clen);
            printf("connfd is :%d\n", connfd);
            add_client(connfd, &pool);                                                                       //新客户端就加入到池结构中
        }

       
        check_clients(&pool);                                                                                //最后服务器进行池中数据检查
    }
}


void init_pool(int listenfd, pool *p)                                   //初始化池结构，各种变量进行初始化
{
   
    int i;
    p->maxi = -1;
    for(i = 0; i < FD_SETSIZE; i++)
        p->clientfd[i] = -1;

   
    p->maxfd = listenfd;
    FD_ZERO(&p->read_set);
    FD_SET(listenfd, &p->read_set);
}

void add_client(int connfd, pool *p)                                       //把数据插入到池结构中
{
    int i;
    p->nready--;
    for(i = 0; i < FD_SETSIZE; i++)  
    {
        if(p->clientfd[i] < 0)
        {
           
            p->clientfd[i] = connfd;
            Rio_readinitb(&p->clientrio[i], connfd);

           
            FD_SET(connfd, &p->read_set);

           
            if(connfd > p->maxfd)
             p->maxfd = connfd;
            if(i > p->maxi)
                p->maxi = i;
            break;
        }
    }

    if(i == FD_SETSIZE)    
         app_error("add_client error: Too many clients");
}


void check_clients(pool *p)                                                        //对池中描述符操作，有就处理，没有就删除
{
    int i, connfd, n;
    char buff[MAXLINE];
    rio_t rio;

    for(i = 0; (i <= p->maxi)&&(p->nready > 0); i++)
    {
        connfd = p->clientfd[i];
        rio = p->clientrio[i];

       
        if((connfd > 0) && (FD_ISSET(connfd, &p->ready_set)))
        {
            p->nready--;
               if((n = Rio_readlineb(&rio, buff, MAXLINE)) != 0)
            {
                byte_cnt += n;
                printf("server received %d (%d total) bytes on fd %d\n",
                                      n, byte_cnt, connfd);
                Rio_writen(connfd, buff, n);
            }
            else    
            {
                Close(connfd);
                FD_CLR(connfd, &p->read_set);
                p->clientfd[i] = -1;
            }
        }
    }
}
  



